package org.hackystat.sdsa.analyzer.model.activity.refactoring;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.logging.Logger;

import javax.xml.datatype.XMLGregorianCalendar;

import jess.Fact;

import org.hackystat.sdsa.analyzer.model.activity.ActivityTestBase;
import org.hackystat.sensorbase.resource.sensordata.jaxb.Properties;
import org.hackystat.sensorbase.resource.sensordata.jaxb.Property;
import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorData;
import org.hackystat.utilities.tstamp.Tstamp;
import org.junit.Test;

/**
 * Tests refactor action.
 * 
 * @author Hongbing Kou
 */
public class TestRefactorActivity extends ActivityTestBase {
  private Logger logger;
  
  /**
   * Prepares test variables.
   * 
   * @throws Exception If any error happens.
   */
  @Override public void setUp() throws Exception {
    super.setUp();
    this.logger = Logger.getLogger(TestRefactorActivity.class.getName());
  }
  
  /**
   * Tests refactoring action with one argument only.
   * 
   * @throws Exception One argument refactoring.
   */
  @Test public void testUnaryRefactoring() throws Exception {
    SensorData sensorData1 = new SensorData();
    XMLGregorianCalendar tstamp = Tstamp.makeTimestamp("2005-01-01T08:30:45.000-10:00");
    sensorData1.setTimestamp(tstamp);
    sensorData1.setResource("file:/C:/cvs/work/com/foo/Bar.java");
    sensorData1.setSensorDataType("DevEvent");

    // Add property
    Properties props = new Properties();
    sensorData1.setProperties(props);

    Property type = new Property();
    type.setKey("Type");
    type.setValue("Edit");
    props.getProperty().add(type);
    
    Property subType = new Property();
    subType.setKey("Subtype");
    subType.setValue("ProgramUnit");
    props.getProperty().add(subType);

    Property subsubType = new Property();
    subsubType.setKey(RefactorActivity.SUBSUB_TYPE);
    subsubType.setValue("Add");
    props.getProperty().add(subsubType);

    Property unitType = new Property();
    unitType.setKey(RefactorActivity.UNIT_TYPE);
    unitType.setValue("Method");
    props.getProperty().add(unitType);

    String method = "String getName()";
    Property fromUnitName = new Property();
    fromUnitName.setKey(UnaryRefactorActivity.UNIT_NAME);
    fromUnitName.setValue(method);
    props.getProperty().add(fromUnitName);

    UnaryRefactorActivity action = new UnaryRefactorActivity(sensorData1, this.logger);
    assertEquals("Test action operator", "ADD", action.getOperator().getName());
    assertEquals("Test action subject type", "METHOD", action.getSubjectType().getName());
    assertEquals("Test action subject name", method, action.getSubjectName());
    assertEquals("Test refactor action string", "2005-01-01T08:30:45.000-10:00 Bar.java ADD METHOD"
        + " {" + method + "}", action.toString());

    Fact f = action.assertActivity(1, engine);
    assertTrue("Test action is asserted to working memory", f.getFactId() >= 0);
  }
  
  /**
   * Tests binary refactoring action.
   * 
   * @throws Exception If error while testing.
   */
  @Test public void testBinaryRefactorAction() throws Exception {
    SensorData sensorData = new SensorData();
    XMLGregorianCalendar tstamp = Tstamp.makeTimestamp("2005-02-15T12:11:30.000-10:00");
    sensorData.setTimestamp(tstamp);
    sensorData.setResource("file:/C:/cvs/hackyRockNRoll.java");
    sensorData.setSensorDataType("DevEvent");

    // Add property
    Properties props = new Properties();
    sensorData.setProperties(props);

    Property type = new Property();
    type.setKey("Type");
    type.setValue("Edit");
    props.getProperty().add(type);
    
    Property subType = new Property();
    subType.setKey("Subtype");
    subType.setValue("ProgramUnit");
    props.getProperty().add(subType);

    Property subsubType = new Property();
    subsubType.setKey(RefactorActivity.SUBSUB_TYPE);
    subsubType.setValue("Rename");
    props.getProperty().add(subsubType);

    Property unitType = new Property();
    unitType.setKey(RefactorActivity.UNIT_TYPE);
    unitType.setValue("Method");
    props.getProperty().add(unitType);

    Property fromUnitName = new Property();
    fromUnitName.setKey(BinaryRefactorActivity.FROM_UNIT_NAME);
    fromUnitName.setValue("void name()");
    props.getProperty().add(fromUnitName);

    Property toUnitName = new Property();
    String method = "String getName()";
    toUnitName.setKey(BinaryRefactorActivity.TO_UNIT_NAME);
    toUnitName.setValue(method);
    props.getProperty().add(toUnitName);

    BinaryRefactorActivity action = new BinaryRefactorActivity(sensorData, this.logger);
    assertEquals("Test action operator", "RENAME", action.getOperator().getName());
    assertEquals("Test action subject type", "METHOD", action.getSubjectType().getName());
    
    assertEquals("Test refactor from subject", "void name()", action.getFromSubject());
    assertEquals("Test refactor to subject", method, action.getToSubject());
    
    String timeString = sensorData.getTimestamp().toString();
    assertEquals("Test refactor action string", 
        "2005-02-15T12:11:30.000-10:00 hackyRockNRoll.java " + 
        "RENAME METHOD {void name() -> String getName()}", action.toString());

  }

  /**
   * Test conversion from activity to Jess fact.
   * 
   * @throws Exception If error occurs.
   */
  @Override public void testJessFactConversion() throws Exception {
    SensorData sensorData = new SensorData();
    XMLGregorianCalendar tstamp = Tstamp.makeTimestamp("2005-02-15T12:11:30.000-10:00");
    sensorData.setTimestamp(tstamp);
    sensorData.setResource("file:/C:/cvs/hackyRockNRoll.java");
    sensorData.setSensorDataType("DevEvent");

    // Add property
    Properties props = new Properties();
    sensorData.setProperties(props);

    Property type = new Property();
    type.setKey("Type");
    type.setValue("Edit");
    props.getProperty().add(type);
    
    Property subType = new Property();
    subType.setKey("Subtype");
    subType.setValue("ProgramUnit");
    props.getProperty().add(subType);

    Property subsubType = new Property();
    subsubType.setKey(RefactorActivity.SUBSUB_TYPE);
    subsubType.setValue("Rename");
    props.getProperty().add(subsubType);

    Property unitType = new Property();
    unitType.setKey(RefactorActivity.UNIT_TYPE);
    unitType.setValue("Method");
    props.getProperty().add(unitType);

    Property fromUnitName = new Property();
    fromUnitName.setKey(BinaryRefactorActivity.FROM_UNIT_NAME);
    fromUnitName.setValue("void name()");
    props.getProperty().add(fromUnitName);

    Property toUnitName = new Property();
    String method = "String getName()";
    toUnitName.setKey(BinaryRefactorActivity.TO_UNIT_NAME);
    toUnitName.setValue(method);
    props.getProperty().add(toUnitName);

    BinaryRefactorActivity action = new BinaryRefactorActivity(sensorData, this.logger);
    Fact f = action.assertActivity(1, engine);
    assertTrue("Test action is asserted to working memory", f.getFactId() >= 0);
  }
}
